///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
*	Contains code for 3x3 matrices.
*	\file		LaborMatrix3x3.h
*	\author		Pierre Terdiman
*	\date		April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __LABORMATRIX3X3_H__
#define __LABORMATRIX3X3_H__
#include "../LaborCoreDef.h"
#include "../Math/LaborMathDecl.h"
#include "LaborPoint3.h"
#include "LaborFPU.h"
NAMESPACE_LABOR3D_BEGIN
// Forward declarations
class CLQuat;

#define	MATRIX3X3_EPSILON		(1.0e-7f)

class  LABORCORE_API CLMatrix3x3
{
public:
	static const float EPSILON;
	static const CLMatrix3x3 ZERO;
	static const CLMatrix3x3 IDENTITY;
public:
	//! Empty constructor
	inline					CLMatrix3x3()									{}
	//! Constructor from 9 values
	inline					CLMatrix3x3(float m00, float m01, float m02, float m10, float m11, float m12, float m20, float m21, float m22)
	{
		m[0][0] = m00;	m[0][1] = m01;	m[0][2] = m02;
		m[1][0] = m10;	m[1][1] = m11;	m[1][2] = m12;
		m[2][0] = m20;	m[2][1] = m21;	m[2][2] = m22;
	}
	//! Copy constructor
	inline					CLMatrix3x3(const CLMatrix3x3& mat)			{ CopyMemory(m, &mat.m, 9*sizeof(float));	}
	//! Destructor
	inline					~CLMatrix3x3()								{}

	//! Assign values
	inline	void			set(float m00, float m01, float m02, float m10, float m11, float m12, float m20, float m21, float m22)
	{
		m[0][0] = m00;	m[0][1] = m01;	m[0][2] = m02;
		m[1][0] = m10;	m[1][1] = m11;	m[1][2] = m12;
		m[2][0] = m20;	m[2][1] = m21;	m[2][2] = m22;
	}

	//! Sets the scale from a Point. The point is put on the diagonal.
	inline	void			setScale(const CLPoint3& p)					{ m[0][0] = p.x;	m[1][1] = p.y;	m[2][2] = p.z;	}

	//! Sets the scale from floats. Values are put on the diagonal.
	inline	void			setScale(float sx, float sy, float sz)		{ m[0][0] = sx;		m[1][1] = sy;	m[2][2] = sz;	}

	//! Scales from a Point. Each row is multiplied by a component.
	inline	void			scale(const CLPoint3& p)
	{
		m[0][0] *= p.x;	m[0][1] *= p.x;	m[0][2] *= p.x;
		m[1][0] *= p.y;	m[1][1] *= p.y;	m[1][2] *= p.y;
		m[2][0] *= p.z;	m[2][1] *= p.z;	m[2][2] *= p.z;
	}

	//! Scales from floats. Each row is multiplied by a value.
	inline	void			scale(float sx, float sy, float sz)
	{
		m[0][0] *= sx;	m[0][1] *= sx;	m[0][2] *= sx;
		m[1][0] *= sy;	m[1][1] *= sy;	m[1][2] *= sy;
		m[2][0] *= sz;	m[2][1] *= sz;	m[2][2] *= sz;
	}

	//! Copy from a CLMatrix3x3
	inline	void			copy(const CLMatrix3x3& source)				{ CopyMemory(m, source.m, 9*sizeof(float));			}

	// Row-column access
	//! Returns a row.
	inline	void			getRow(const unsigned int r, CLPoint3& p)	const	{ p.x = m[r][0];	p.y = m[r][1];	p.z = m[r][2];	}
	//! Returns a row.
	inline	const CLPoint3&	getRow(const unsigned int r)				const	{ return *(const CLPoint3*)&m[r][0];	}
	//! Returns a row.
	inline	CLPoint3&			getRow(const unsigned int r)						{ return *(CLPoint3*)&m[r][0];			}
	//! Sets a row.
	inline	void			setRow(const unsigned int r, const CLPoint3& p)		{ m[r][0] = p.x;	m[r][1] = p.y;	m[r][2] = p.z;	}
	//! Returns a column.
	inline	void			getCol(const unsigned int c, CLPoint3& p)	const		{ p.x = m[0][c];	p.y = m[1][c];	p.z = m[2][c];	}
	//! Sets a column.
	inline	void			setCol(const unsigned int c, const CLPoint3& p)		{ m[0][c] = p.x;	m[1][c] = p.y;	m[2][c] = p.z;	}

	//! Computes the trace. The trace is the sum of the 3 diagonal components.
	inline	float			trace()					const				{ return m[0][0] + m[1][1] + m[2][2];				}
	//! Clears the matrix.
	inline	void			zero()										{ ZeroMemory(&m, sizeof(m));						}
	//! Sets the identity matrix.
	inline	void			identity()									{ zero(); m[0][0] = m[1][1] = m[2][2] = 1.0f; 		}
	//! Checks for identity
	inline	bool			isIdentity()			const
	{
		if(IR(m[0][0])!=IEEE_1_0)	return false;
		if(IR(m[0][1])!=0)			return false;
		if(IR(m[0][2])!=0)			return false;

		if(IR(m[1][0])!=0)			return false;
		if(IR(m[1][1])!=IEEE_1_0)	return false;
		if(IR(m[1][2])!=0)			return false;

		if(IR(m[2][0])!=0)			return false;
		if(IR(m[2][1])!=0)			return false;
		if(IR(m[2][2])!=IEEE_1_0)	return false;

		return true;
	}

	//! Checks matrix validity
	inline	bool			isValid()				const
	{
		for(unsigned int j=0;j<3;j++)
		{
			for(unsigned int i=0;i<3;i++)
			{
				if(!isValidFloat(m[j][i]))	return false;
			}
		}
		return true;
	}

	//! Makes a skew-symmetric matrix (a.k.a. Star(*) Matrix)
	//!	[  0.0  -a.z   a.y ]
	//!	[  a.z   0.0  -a.x ]
	//!	[ -a.y   a.x   0.0 ]
	//! This is also called a "cross matrix" since for any vectors A and B,
	//! A^B = Skew(A) * B = - B * Skew(A);
	inline	void			skewSymmetric(const CLPoint3& a)
	{
		m[0][0] = 0.0f;
		m[0][1] = -a.z;
		m[0][2] = a.y;

		m[1][0] = a.z;
		m[1][1] = 0.0f;
		m[1][2] = -a.x;

		m[2][0] = -a.y;
		m[2][1] = a.x;
		m[2][2] = 0.0f;
	}

	//! Negates the matrix
	inline	void			neg()
	{
		m[0][0] = -m[0][0];	m[0][1] = -m[0][1];	m[0][2] = -m[0][2];
		m[1][0] = -m[1][0];	m[1][1] = -m[1][1];	m[1][2] = -m[1][2];
		m[2][0] = -m[2][0];	m[2][1] = -m[2][1];	m[2][2] = -m[2][2];
	}

	//! Neg from another matrix
	inline	void			neg(const CLMatrix3x3& mat)
	{
		m[0][0] = -mat.m[0][0];	m[0][1] = -mat.m[0][1];	m[0][2] = -mat.m[0][2];
		m[1][0] = -mat.m[1][0];	m[1][1] = -mat.m[1][1];	m[1][2] = -mat.m[1][2];
		m[2][0] = -mat.m[2][0];	m[2][1] = -mat.m[2][1];	m[2][2] = -mat.m[2][2];
	}

	//! Add another matrix
	inline	void			add(const CLMatrix3x3& mat)
	{
		m[0][0] += mat.m[0][0];	m[0][1] += mat.m[0][1];	m[0][2] += mat.m[0][2];
		m[1][0] += mat.m[1][0];	m[1][1] += mat.m[1][1];	m[1][2] += mat.m[1][2];
		m[2][0] += mat.m[2][0];	m[2][1] += mat.m[2][1];	m[2][2] += mat.m[2][2];
	}

	//! Sub another matrix
	inline	void			sub(const CLMatrix3x3& mat)
	{
		m[0][0] -= mat.m[0][0];	m[0][1]	-= mat.m[0][1];	m[0][2] -= mat.m[0][2];
		m[1][0] -= mat.m[1][0];	m[1][1] -= mat.m[1][1];	m[1][2] -= mat.m[1][2];
		m[2][0] -= mat.m[2][0];	m[2][1] -= mat.m[2][1];	m[2][2] -= mat.m[2][2];
	}
	//! Mac
	inline	void			mac(const CLMatrix3x3& a, const CLMatrix3x3& b, float s)
	{
		m[0][0] = a.m[0][0] + b.m[0][0] * s;
		m[0][1] = a.m[0][1] + b.m[0][1] * s;
		m[0][2] = a.m[0][2] + b.m[0][2] * s;

		m[1][0] = a.m[1][0] + b.m[1][0] * s;
		m[1][1] = a.m[1][1] + b.m[1][1] * s;
		m[1][2] = a.m[1][2] + b.m[1][2] * s;

		m[2][0] = a.m[2][0] + b.m[2][0] * s;
		m[2][1] = a.m[2][1] + b.m[2][1] * s;
		m[2][2] = a.m[2][2] + b.m[2][2] * s;
	}
	//! Mac
	inline	void			mac(const CLMatrix3x3& a, float s)
	{
		m[0][0] += a.m[0][0] * s;	m[0][1] += a.m[0][1] * s;	m[0][2] += a.m[0][2] * s;
		m[1][0] += a.m[1][0] * s;	m[1][1] += a.m[1][1] * s;	m[1][2] += a.m[1][2] * s;
		m[2][0] += a.m[2][0] * s;	m[2][1] += a.m[2][1] * s;	m[2][2] += a.m[2][2] * s;
	}

	//! this = A * s
	inline	void			mult(const CLMatrix3x3& a, float s)
	{
		m[0][0] = a.m[0][0] * s;	m[0][1] = a.m[0][1] * s;	m[0][2] = a.m[0][2] * s;
		m[1][0] = a.m[1][0] * s;	m[1][1] = a.m[1][1] * s;	m[1][2] = a.m[1][2] * s;
		m[2][0] = a.m[2][0] * s;	m[2][1] = a.m[2][1] * s;	m[2][2] = a.m[2][2] * s;
	}

	inline	void			add(const CLMatrix3x3& a, const CLMatrix3x3& b)
	{
		m[0][0] = a.m[0][0] + b.m[0][0];	m[0][1] = a.m[0][1] + b.m[0][1];	m[0][2] = a.m[0][2] + b.m[0][2];
		m[1][0] = a.m[1][0] + b.m[1][0];	m[1][1] = a.m[1][1] + b.m[1][1];	m[1][2] = a.m[1][2] + b.m[1][2];
		m[2][0] = a.m[2][0] + b.m[2][0];	m[2][1] = a.m[2][1] + b.m[2][1];	m[2][2] = a.m[2][2] + b.m[2][2];
	}

	inline	void			sub(const CLMatrix3x3& a, const CLMatrix3x3& b)
	{
		m[0][0] = a.m[0][0] - b.m[0][0];	m[0][1] = a.m[0][1] - b.m[0][1];	m[0][2] = a.m[0][2] - b.m[0][2];
		m[1][0] = a.m[1][0] - b.m[1][0];	m[1][1] = a.m[1][1] - b.m[1][1];	m[1][2] = a.m[1][2] - b.m[1][2];
		m[2][0] = a.m[2][0] - b.m[2][0];	m[2][1] = a.m[2][1] - b.m[2][1];	m[2][2] = a.m[2][2] - b.m[2][2];
	}

	//! this = a * b
	inline	void			mult(const CLMatrix3x3& a, const CLMatrix3x3& b)
	{
		m[0][0] = a.m[0][0] * b.m[0][0] + a.m[0][1] * b.m[1][0] + a.m[0][2] * b.m[2][0];
		m[0][1] = a.m[0][0] * b.m[0][1] + a.m[0][1] * b.m[1][1] + a.m[0][2] * b.m[2][1];
		m[0][2] = a.m[0][0] * b.m[0][2] + a.m[0][1] * b.m[1][2] + a.m[0][2] * b.m[2][2];
		m[1][0] = a.m[1][0] * b.m[0][0] + a.m[1][1] * b.m[1][0] + a.m[1][2] * b.m[2][0];
		m[1][1] = a.m[1][0] * b.m[0][1] + a.m[1][1] * b.m[1][1] + a.m[1][2] * b.m[2][1];
		m[1][2] = a.m[1][0] * b.m[0][2] + a.m[1][1] * b.m[1][2] + a.m[1][2] * b.m[2][2];
		m[2][0] = a.m[2][0] * b.m[0][0] + a.m[2][1] * b.m[1][0] + a.m[2][2] * b.m[2][0];
		m[2][1] = a.m[2][0] * b.m[0][1] + a.m[2][1] * b.m[1][1] + a.m[2][2] * b.m[2][1];
		m[2][2] = a.m[2][0] * b.m[0][2] + a.m[2][1] * b.m[1][2] + a.m[2][2] * b.m[2][2];
	}

	//! this = transpose(a) * b
	inline	void			multAtB(const CLMatrix3x3& a, const CLMatrix3x3& b)
	{
		m[0][0] = a.m[0][0] * b.m[0][0] + a.m[1][0] * b.m[1][0] + a.m[2][0] * b.m[2][0];
		m[0][1] = a.m[0][0] * b.m[0][1] + a.m[1][0] * b.m[1][1] + a.m[2][0] * b.m[2][1];
		m[0][2] = a.m[0][0] * b.m[0][2] + a.m[1][0] * b.m[1][2] + a.m[2][0] * b.m[2][2];
		m[1][0] = a.m[0][1] * b.m[0][0] + a.m[1][1] * b.m[1][0] + a.m[2][1] * b.m[2][0];
		m[1][1] = a.m[0][1] * b.m[0][1] + a.m[1][1] * b.m[1][1] + a.m[2][1] * b.m[2][1];
		m[1][2] = a.m[0][1] * b.m[0][2] + a.m[1][1] * b.m[1][2] + a.m[2][1] * b.m[2][2];
		m[2][0] = a.m[0][2] * b.m[0][0] + a.m[1][2] * b.m[1][0] + a.m[2][2] * b.m[2][0];
		m[2][1] = a.m[0][2] * b.m[0][1] + a.m[1][2] * b.m[1][1] + a.m[2][2] * b.m[2][1];
		m[2][2] = a.m[0][2] * b.m[0][2] + a.m[1][2] * b.m[1][2] + a.m[2][2] * b.m[2][2];
	}

	//! this = a * transpose(b)
	inline	void			multABt(const CLMatrix3x3& a, const CLMatrix3x3& b)
	{
		m[0][0] = a.m[0][0] * b.m[0][0] + a.m[0][1] * b.m[0][1] + a.m[0][2] * b.m[0][2];
		m[0][1] = a.m[0][0] * b.m[1][0] + a.m[0][1] * b.m[1][1] + a.m[0][2] * b.m[1][2];
		m[0][2] = a.m[0][0] * b.m[2][0] + a.m[0][1] * b.m[2][1] + a.m[0][2] * b.m[2][2];
		m[1][0] = a.m[1][0] * b.m[0][0] + a.m[1][1] * b.m[0][1] + a.m[1][2] * b.m[0][2];
		m[1][1] = a.m[1][0] * b.m[1][0] + a.m[1][1] * b.m[1][1] + a.m[1][2] * b.m[1][2];
		m[1][2] = a.m[1][0] * b.m[2][0] + a.m[1][1] * b.m[2][1] + a.m[1][2] * b.m[2][2];
		m[2][0] = a.m[2][0] * b.m[0][0] + a.m[2][1] * b.m[0][1] + a.m[2][2] * b.m[0][2];
		m[2][1] = a.m[2][0] * b.m[1][0] + a.m[2][1] * b.m[1][1] + a.m[2][2] * b.m[1][2];
		m[2][2] = a.m[2][0] * b.m[2][0] + a.m[2][1] * b.m[2][1] + a.m[2][2] * b.m[2][2];
	}

	//! Makes a rotation matrix mapping vector "from" to vector "to".
	CLMatrix3x3&		fromTo(const CLPoint3& from, const CLPoint3& to);

	//! Set a rotation matrix around the X axis.
	//!		 1		0		0
	//!	RX = 0		cx		sx
	//!		 0		-sx		cx
	void			rotX(float angle);
	//! Set a rotation matrix around the Y axis.
	//!		 cy		0		-sy
	//!	RY = 0		1		0
	//!		 sy		0		cy
	void			rotY(float angle);
	//! Set a rotation matrix around the Z axis.
	//!		 cz		sz		0
	//!	RZ = -sz	cz		0
	//!		 0		0		1
	void			rotZ(float angle);
	//!			cy		sx.sy		-sy.cx
	//!	RY.RX	0		cx			sx
	//!			sy		-sx.cy		cx.cy
	void			rotYX(float y, float x);

	//! Make a rotation matrix about an arbitrary axis
	CLMatrix3x3&		rot(float angle, const CLPoint3& axis);

	//! Transpose the matrix.
	void			transpose()
	{
		IR(m[1][0]) ^= IR(m[0][1]);	IR(m[0][1]) ^= IR(m[1][0]);	IR(m[1][0]) ^= IR(m[0][1]);
		IR(m[2][0]) ^= IR(m[0][2]);	IR(m[0][2]) ^= IR(m[2][0]);	IR(m[2][0]) ^= IR(m[0][2]);
		IR(m[2][1]) ^= IR(m[1][2]);	IR(m[1][2]) ^= IR(m[2][1]);	IR(m[2][1]) ^= IR(m[1][2]);
	}

	//! this = Transpose(a)
	void			transpose(const CLMatrix3x3& a)
	{
		m[0][0] = a.m[0][0];	m[0][1] = a.m[1][0];	m[0][2] = a.m[2][0];
		m[1][0] = a.m[0][1];	m[1][1] = a.m[1][1];	m[1][2] = a.m[2][1];
		m[2][0] = a.m[0][2];	m[2][1] = a.m[1][2];	m[2][2] = a.m[2][2];
	}

	//! Compute the determinant of the matrix. We use the rule of Sarrus.
	float			determinant()					const
	{
		return (m[0][0]*m[1][1]*m[2][2] + m[0][1]*m[1][2]*m[2][0] + m[0][2]*m[1][0]*m[2][1])
			-  (m[2][0]*m[1][1]*m[0][2] + m[2][1]*m[1][2]*m[0][0] + m[2][2]*m[1][0]*m[0][1]);
	}
	/*
	//! Compute a cofactor. Used for matrix inversion.
	float			CoFactor(ubyte row, ubyte column)	const
	{
	static sdword gIndex[3+2] = { 0, 1, 2, 0, 1 };
	return	(m[gIndex[row+1]][gIndex[column+1]]*m[gIndex[row+2]][gIndex[column+2]] - m[gIndex[row+2]][gIndex[column+1]]*m[gIndex[row+1]][gIndex[column+2]]);
	}
	*/
	//! Invert the matrix. Determinant must be different from zero, else matrix can't be inverted.
	CLMatrix3x3&		invert()
	{
		float Det = determinant();	// Must be !=0
		float OneOverDet = 1.0f / Det;

		CLMatrix3x3 Temp;
		Temp.m[0][0] = +(m[1][1] * m[2][2] - m[2][1] * m[1][2]) * OneOverDet;
		Temp.m[1][0] = -(m[1][0] * m[2][2] - m[2][0] * m[1][2]) * OneOverDet;
		Temp.m[2][0] = +(m[1][0] * m[2][1] - m[2][0] * m[1][1]) * OneOverDet;
		Temp.m[0][1] = -(m[0][1] * m[2][2] - m[2][1] * m[0][2]) * OneOverDet;
		Temp.m[1][1] = +(m[0][0] * m[2][2] - m[2][0] * m[0][2]) * OneOverDet;
		Temp.m[2][1] = -(m[0][0] * m[2][1] - m[2][0] * m[0][1]) * OneOverDet;
		Temp.m[0][2] = +(m[0][1] * m[1][2] - m[1][1] * m[0][2]) * OneOverDet;
		Temp.m[1][2] = -(m[0][0] * m[1][2] - m[1][0] * m[0][2]) * OneOverDet;
		Temp.m[2][2] = +(m[0][0] * m[1][1] - m[1][0] * m[0][1]) * OneOverDet;

		*this = Temp;

		return	*this;
	}

	CLMatrix3x3&		normalize();

	//! this = exp(a)
	CLMatrix3x3&		exp(const CLMatrix3x3& a);

	void fromQuat(const CLQuat &q);
	void fromQuatL2(const CLQuat &q, float l2);

	// Arithmetic operators
	//! Operator for CLMatrix3x3 Plus = CLMatrix3x3 + CLMatrix3x3;
	inline	CLMatrix3x3		operator+(const CLMatrix3x3& mat)	const
	{
		return CLMatrix3x3(
			m[0][0] + mat.m[0][0],	m[0][1] + mat.m[0][1],	m[0][2] + mat.m[0][2],
			m[1][0] + mat.m[1][0],	m[1][1] + mat.m[1][1],	m[1][2] + mat.m[1][2],
			m[2][0] + mat.m[2][0],	m[2][1] + mat.m[2][1],	m[2][2] + mat.m[2][2]);
	}

	//! Operator for CLMatrix3x3 Minus = CLMatrix3x3 - CLMatrix3x3;
	inline	CLMatrix3x3		operator-(const CLMatrix3x3& mat)	const
	{
		return CLMatrix3x3(
			m[0][0] - mat.m[0][0],	m[0][1] - mat.m[0][1],	m[0][2] - mat.m[0][2],
			m[1][0] - mat.m[1][0],	m[1][1] - mat.m[1][1],	m[1][2] - mat.m[1][2],
			m[2][0] - mat.m[2][0],	m[2][1] - mat.m[2][1],	m[2][2] - mat.m[2][2]);
	}

	//! Operator for CLMatrix3x3 Mul = CLMatrix3x3 * CLMatrix3x3;
	inline	CLMatrix3x3		operator*(const CLMatrix3x3& mat)	const
	{
		return CLMatrix3x3(
			m[0][0]*mat.m[0][0] + m[0][1]*mat.m[1][0] + m[0][2]*mat.m[2][0],
			m[0][0]*mat.m[0][1] + m[0][1]*mat.m[1][1] + m[0][2]*mat.m[2][1],
			m[0][0]*mat.m[0][2] + m[0][1]*mat.m[1][2] + m[0][2]*mat.m[2][2],

			m[1][0]*mat.m[0][0] + m[1][1]*mat.m[1][0] + m[1][2]*mat.m[2][0],
			m[1][0]*mat.m[0][1] + m[1][1]*mat.m[1][1] + m[1][2]*mat.m[2][1],
			m[1][0]*mat.m[0][2] + m[1][1]*mat.m[1][2] + m[1][2]*mat.m[2][2],

			m[2][0]*mat.m[0][0] + m[2][1]*mat.m[1][0] + m[2][2]*mat.m[2][0],
			m[2][0]*mat.m[0][1] + m[2][1]*mat.m[1][1] + m[2][2]*mat.m[2][1],
			m[2][0]*mat.m[0][2] + m[2][1]*mat.m[1][2] + m[2][2]*mat.m[2][2]);
	}

	//! Operator for Point Mul = CLMatrix3x3 * Point;
	inline	CLPoint3			operator*(const CLPoint3& v)		const		
	{ 
		float x = getRow(0)|v;
		float y = getRow(1)|v;
		float z = getRow(2)|v;

		return CLPoint3( x,  y,  z);
	}

	//! Operator for CLMatrix3x3 Mul = CLMatrix3x3 * float;
	inline	CLMatrix3x3		operator*(float s)				const
	{
		return CLMatrix3x3(
			m[0][0]*s,	m[0][1]*s,	m[0][2]*s,
			m[1][0]*s,	m[1][1]*s,	m[1][2]*s,
			m[2][0]*s,	m[2][1]*s,	m[2][2]*s);
	}

	//! Operator for CLMatrix3x3 Mul = float * CLMatrix3x3;
	inline	friend CLMatrix3x3 operator*(float s, const CLMatrix3x3& mat)
	{
		return CLMatrix3x3(
			s*mat.m[0][0],	s*mat.m[0][1],	s*mat.m[0][2],
			s*mat.m[1][0],	s*mat.m[1][1],	s*mat.m[1][2],
			s*mat.m[2][0],	s*mat.m[2][1],	s*mat.m[2][2]);
	}

	//! Operator for CLMatrix3x3 Div = CLMatrix3x3 / float;
	inline	CLMatrix3x3		operator/(float s)				const
	{
		if (s)	s = 1.0f / s;
		return CLMatrix3x3(
			m[0][0]*s,	m[0][1]*s,	m[0][2]*s,
			m[1][0]*s,	m[1][1]*s,	m[1][2]*s,
			m[2][0]*s,	m[2][1]*s,	m[2][2]*s);
	}

	//! Operator for CLMatrix3x3 Div = float / CLMatrix3x3;
	inline	friend CLMatrix3x3 operator/(float s, const CLMatrix3x3& mat)
	{
		return CLMatrix3x3(
			s/mat.m[0][0],	s/mat.m[0][1],	s/mat.m[0][2],
			s/mat.m[1][0],	s/mat.m[1][1],	s/mat.m[1][2],
			s/mat.m[2][0],	s/mat.m[2][1],	s/mat.m[2][2]);
	}

	//! Operator for CLMatrix3x3 += CLMatrix3x3
	inline	CLMatrix3x3&		operator+=(const CLMatrix3x3& mat)
	{
		m[0][0] += mat.m[0][0];		m[0][1] += mat.m[0][1];		m[0][2] += mat.m[0][2];
		m[1][0] += mat.m[1][0];		m[1][1] += mat.m[1][1];		m[1][2] += mat.m[1][2];
		m[2][0] += mat.m[2][0];		m[2][1] += mat.m[2][1];		m[2][2] += mat.m[2][2];
		return	*this;
	}

	//! Operator for CLMatrix3x3 -= CLMatrix3x3
	inline	CLMatrix3x3&		operator-=(const CLMatrix3x3& mat)
	{
		m[0][0] -= mat.m[0][0];		m[0][1] -= mat.m[0][1];		m[0][2] -= mat.m[0][2];
		m[1][0] -= mat.m[1][0];		m[1][1] -= mat.m[1][1];		m[1][2] -= mat.m[1][2];
		m[2][0] -= mat.m[2][0];		m[2][1] -= mat.m[2][1];		m[2][2] -= mat.m[2][2];
		return	*this;
	}

	//! Operator for CLMatrix3x3 *= CLMatrix3x3
	inline	CLMatrix3x3&		operator*=(const CLMatrix3x3& mat)
	{
		CLPoint3 TempRow;

		getRow(0, TempRow);
		m[0][0] = TempRow.x*mat.m[0][0] + TempRow.y*mat.m[1][0] + TempRow.z*mat.m[2][0];
		m[0][1] = TempRow.x*mat.m[0][1] + TempRow.y*mat.m[1][1] + TempRow.z*mat.m[2][1];
		m[0][2] = TempRow.x*mat.m[0][2] + TempRow.y*mat.m[1][2] + TempRow.z*mat.m[2][2];

		getRow(1, TempRow);
		m[1][0] = TempRow.x*mat.m[0][0] + TempRow.y*mat.m[1][0] + TempRow.z*mat.m[2][0];
		m[1][1] = TempRow.x*mat.m[0][1] + TempRow.y*mat.m[1][1] + TempRow.z*mat.m[2][1];
		m[1][2] = TempRow.x*mat.m[0][2] + TempRow.y*mat.m[1][2] + TempRow.z*mat.m[2][2];

		getRow(2, TempRow);
		m[2][0] = TempRow.x*mat.m[0][0] + TempRow.y*mat.m[1][0] + TempRow.z*mat.m[2][0];
		m[2][1] = TempRow.x*mat.m[0][1] + TempRow.y*mat.m[1][1] + TempRow.z*mat.m[2][1];
		m[2][2] = TempRow.x*mat.m[0][2] + TempRow.y*mat.m[1][2] + TempRow.z*mat.m[2][2];
		return	*this;
	}

	//! Operator for Matrix3x3 *= float
	inline	CLMatrix3x3&		operator*=(float s)
	{
		m[0][0] *= s;	m[0][1] *= s;	m[0][2] *= s;
		m[1][0] *= s;	m[1][1] *= s;	m[1][2] *= s;
		m[2][0] *= s;	m[2][1] *= s;	m[2][2] *= s;
		return	*this;
	}

	//! Operator for CLMatrix3x3 /= float
	inline	CLMatrix3x3&		operator/=(float s)
	{
		if (s)	s = 1.0f / s;
		m[0][0] *= s;	m[0][1] *= s;	m[0][2] *= s;
		m[1][0] *= s;	m[1][1] *= s;	m[1][2] *= s;
		m[2][0] *= s;	m[2][1] *= s;	m[2][2] *= s;
		return	*this;
	}

	// Cast operators
	//! Cast a CLMatrix3x3 to a Matrix4x4.
	operator CLMatrix4x4()	const;
	//! Cast a CLMatrix3x3 to a Quat.
	operator CLQuat()		const;

	inline	const CLPoint3&	operator[](int row)		const	{ return *(const CLPoint3*)&m[row][0];	}
	inline	CLPoint3&			operator[](int row)				{ return *(CLPoint3*)&m[row][0];		}

public:

	float			m[3][3];

};

NAMESPACE_LABOR3D_END

#endif // __LABORMATRIX3X3_H__

